<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Iterator 和 for...of 循环</title>
	</head>
	<body>
		<p>JavaScript 原有的表示“集合”的数据结构，主要是数组（Array）和对象（Object），ES6
			又添加了Map和Set。这样就有了四种数据集合，用户还可以组合使用它们，定义自己的数据结构，比如数组的成员是Map，Map的成员是对象。这样就需要一种统一的接口机制，来处理所有不同的数据结构。</p>
		<p>遍历器（Iterator）就是这样一种机制。它是一种接口，为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口，就可以完成遍历操作（即依次处理该数据结构的所有成员）</p>
		<p>Iterator 的作用有三个：一是为各种数据结构，提供一个统一的、简便的访问接口；二是使得数据结构的成员能够按某种次序排列；三是 ES6 创造了一种新的遍历命令for...of循环，Iterator
			接口主要供for...of消费。</p>

		<script type="text/javascript">
			// ES6 规定，默认的 Iterator 接口部署在数据结构的Symbol.iterator属性，或者说，一个数据结构只要具有Symbol.iterator属性，就可以认为是“可遍历的”（iterable）。Symbol.iterator属性本身是一个函数，就是当前数据结构默认的遍历器生成函数。
			let arr = ['a', 'b', 'c'];
			let iter = arr[Symbol.iterator]();
			iter.next() // { value: 'a', done: false }         
			iter.next() // { value: 'b', done: false }
			iter.next() // { value: 'c', done: false }
			iter.next() // { value: undefined, done: true }

			// 对于类似数组的对象（存在数值键名和length属性），部署 Iterator 接口，有一个简便方法，就是Symbol.iterator方法直接引用数组的 Iterator 接口
			// 注意，普通对象部署数组的Symbol.iterator方法，并无效果，因为会报错
			let iterable = {
				0: 'a',
				1: 'b',
				2: 'c',
				length: 3,
				[Symbol.iterator]: Array.prototype[Symbol.iterator]
			};
			console.log(...[...iterable]); // 'a' 'b' 'c'

			// for...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象（比如arguments对象、DOM NodeList 对象）、Generator 对象，以及字符串
			// JavaScript 原有的for...in循环，只能获得对象的键名，不能直接获取键值。ES6 提供for...of循环，允许遍历获得键值
			var array = ['a', 'b', 'c', 'd'];
			//遍历键名
			for (let a in array) {
				console.log(a); // 0 1 2 3
			}
			//遍历键值
			for (let a of array) {
				console.log(a); // a b c d
			}
		</script>
	</body>
</html>
